/*
 * settings.c
 *
 *   Created on: 2023-05-15
 *       Author: lidq
 */

#include <settings.hpp>
#include <utils.hpp>

// 读写文件每一行字符数
#define LINESIZE	  (1024)
#define MAX_SIZE_PATH (1024 * 1024)
#define NAME_SETTINGS "settings.ini"

// 全局变量，配置参数
settings_s* g_Settings;

// [由Python生成
extern int py_settings_key_value_set(char* key, char* value);
extern int py_settings_key_value_get(char* key, char* value);
extern void py_settings_key_value_save(int fd, char* line, int line_size);
extern void py_settings_key_value_display(void (*callback)(const char*, char*, void*), void* arg);
extern void py_settings_reset(void);
// 由Python生成]

static Settings* s_Settings = nullptr;

Settings* Settings::Instance(void)
{
	if (s_Settings == nullptr)
	{
		s_Settings = new Settings();
	}
	return s_Settings;
}

Settings::Settings()
	: TaskRun()
	, m_AutoSave()
	, m_SemSigSave(0)
	, m_SemRwSave(1)
	, m_NeedSave(0)
{
	g_Settings = (settings_s*)malloc(sizeof(settings_s));

	// 由Python生成，恢复默认设置
	py_settings_reset();

	// 从配置文件中载入
	LoadFromFile();
	// 保存到配置文件
	SaveToFile();
}

Settings::~Settings()
{
	SaveToFile();
	Save();
}

// 字符串去全部空格
void Settings::StringTrimedAll(char* out, char* in, int len)
{
	char* p0 = out;
	char* p1 = in;

	while (*p1 != 0)
	{
		if (*p1 != ' ')
		{
			*p0++ = *p1;
		}
		p1++;
	}
	*p0 = 0;
}

void Settings::Start(void* arg)
{
	TaskRun::Start(arg);

	m_AutoSave.Start(this);
}

void Settings::Save(void)
{
	m_SemRwSave.Wait();
	m_NeedSave = 1;
	m_SemRwSave.Post();
	// 发信号表示需要保存
	m_SemSigSave.Post();
}

void Settings::Load(void)
{
	LoadFromFile();
}

// 从一行配置中的值载入到变量中
void Settings::LoadValue(char* line)
{
	char* str = (char*)malloc(LINESIZE);

	// 去掉所有空格
	StringTrimedAll(str, line, LINESIZE);

	char* p = strstr(str, "=");
	if (p != NULL)
	{
		*p			= 0;
		char* key	= str;
		char* value = p + 1;
		// 载入配置
		py_settings_key_value_set(key, value);
	}
	free(str);
}

// 载入配置文件
void Settings::LoadFromFile(void)
{
	// 打开配置文件
	char* path = GetPrgFilePath(NAME_SETTINGS);
	int fd	   = open(path, O_CREAT | O_RDONLY, 0666);
	free(path);
	if (fd < 0)
	{
		LOGE("can not open setting file.\n");
		return;
	}

	char* line = (char*)malloc(LINESIZE);
	char* p	   = line;
	char ch	   = 0;
	while (1)
	{
		// 按行读取
		int len = read(fd, &ch, sizeof(char));
		if (len <= 0)
		{
			break;
		}
		if (ch == '\r' || ch == '\n')
		{
			*p = 0;
			// 从一行里载入配置参数
			LoadValue(line);
			p = line;
		}
		else
		{
			*p++ = ch;
		}
	}

	free(line);
	close(fd);
}

// 保存配置文件
void Settings::SaveToFile(void)
{
	// 打开配置文件
	char* path = GetPrgFilePath(NAME_SETTINGS);
	int fd	   = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0666);
	free(path);
	if (fd < 0)
	{
		LOGE("can not save setting file.\n");
		return;
	}

	char* line = (char*)malloc(LINESIZE);
	// 由Python生成，保存配置参数到文件
	py_settings_key_value_save(fd, line, LINESIZE);

	free(line);
	fsync(fd);
	close(fd);
}

void Settings::Run(void* arg)
{
	int needSave = 0;
	while (1)
	{
		// 等待信号量
		m_SemSigSave.Wait();
		m_SemRwSave.Wait();
		if (m_NeedSave)
		{
			needSave   = 1;
			m_NeedSave = 0;
		}
		m_SemRwSave.Post();
		// 保存配置参数到文件
		if (needSave)
		{
			needSave = 0;
			SaveToFile();
		}
	}
}

SettingsAutoSave::SettingsAutoSave()
	: TaskRun()
{
}

SettingsAutoSave::~SettingsAutoSave()
{
}

void SettingsAutoSave::Run(void* arg)
{
	if (arg == nullptr)
	{
		return;
	}
	Settings* pSetting = (Settings*)arg;

	while (1)
	{
		uint32_t ms = g_Settings->log_force_save_ms;
		if (ms == 0)
		{
			ms = 15000;
		}
		pSetting->Save();
		usleep(ms * 1000);
	}
}

/* @RegistMainFunction */
int settings_main(int argc, char** argv)
{
	if (argc == 2 && strcmp(argv[1], "show") == 0)
	{
		py_settings_key_value_display(NULL, NULL);
		return 0;
	}
	if (argc == 3 && strcmp(argv[1], "show") == 0)
	{
		char value[200] = { 0 };
		if (py_settings_key_value_get(argv[2], value) != 0)
		{
			LOGE("setting not found.\n");
			return -1;
		}
		LOGI("%s = %s\n", argv[2], value);
		return 0;
	}
	if (argc == 4 && strcmp(argv[1], "set") == 0)
	{
		char value[200] = { 0 };
		if (py_settings_key_value_get(argv[2], value) != 0)
		{
			LOGE("setting not found.\n");
			return -1;
		}

		if (py_settings_key_value_set(argv[2], argv[3]) != 0)
		{
			LOGE("setting not found.\n");
			return -1;
		}
		LOGI("set %s [%s => %s]\n", argv[2], value, argv[3]);
		Settings::Instance()->Save();
		return 0;
	}
	if (argc == 2 && strcmp(argv[1], "save") == 0)
	{
		Settings::Instance()->Save();
		LOGI("settings save to file.\n");
		return 0;
	}
	if (argc == 2 && strcmp(argv[1], "load") == 0)
	{
		Settings::Instance()->Load();
		LOGI("settings load from file.\n");
		return 0;
	}

	LOGE("cmd not found.\n");
	return -1;
}